﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Net;
using System.Security.Authentication;
using System.Text.RegularExpressions;
using WebSocket4Net;

namespace CommonUtil {
    public class SocketClient : WebSocket {
        private Dictionary<string, List<Func<object, object>>> EventHandlers = new Dictionary<string, List<Func<object, object>>>();
        public SocketClient(string uri, string subProtocol, WebSocketVersion version) : base(uri, subProtocol, version) {

            Error += Socket_Error;
            Opened += Socket_Opened;
            Closed += Socket_Closed;
            MessageReceived += Socket_MessageReceived;
        }

        public SocketClient(string uri, string subProtocol = "", List<KeyValuePair<string, string>> cookies = null, List<KeyValuePair<string, string>> customHeaderItems = null, string userAgent = "", string origin = "", WebSocketVersion version = WebSocketVersion.None, EndPoint httpConnectProxy = null, SslProtocols sslProtocols = SslProtocols.None, int receiveBufferSize = 0) : base(uri, subProtocol, cookies, customHeaderItems, userAgent, origin, version, httpConnectProxy, sslProtocols, receiveBufferSize) {

            Error += Socket_Error;
            Opened += Socket_Opened;
            Closed += Socket_Closed;
            MessageReceived += Socket_MessageReceived;
        }

        private void Socket_Opened(object sender, EventArgs e) {
            ExcuteFunc("connection");
        }

        private void Socket_Closed(object sender, EventArgs e) {
            ExcuteFunc("close");
            Open();
        }

        private void Socket_Error(object sender, SuperSocket.ClientEngine.ErrorEventArgs e) {
            ExcuteFunc("error", e.Exception);
        }

        private void ExcuteFunc(string eventName, object s = null) {
            if (EventHandlers[eventName] != null) {
                List<Func<object, object>> eventList = EventHandlers[eventName];
                JArray jArray = new JArray();
                foreach (Func<object, object> fn in eventList) {
                    try {
                        object res = fn(s);
                        jArray.Add(res);
                    } catch (Exception ex) {
                        jArray.Add(ex);
                    }
                }
                if (!Regex.IsMatch(eventName, "connection|close|error")) {
                    Emit($"res:{eventName}", jArray);
                }
            }
        }

        private void Socket_MessageReceived(object sender, MessageReceivedEventArgs e) {
            dynamic msg = JObject.Parse(e.Message);
            string eventName = msg["eventName"];
            ExcuteFunc(eventName, msg["data"]);
        }

        public void On(string eventName, Func<object, object> fn) {
            if (string.IsNullOrWhiteSpace(eventName)) throw new Exception("eventName 是必须的");

            if (!EventHandlers.ContainsKey(eventName)) EventHandlers[eventName] = new List<Func<object, object>>();

            EventHandlers[eventName].Add(fn);
        }

        public void Emit(string eventName, JObject param = null) {
            if (string.IsNullOrWhiteSpace(eventName)) throw new Exception("eventName 是必须的");

            JObject jObject = new JObject { ["eventName"] = eventName };
            if (param != null) jObject["data"] = param;

            Send(JsonConvert.SerializeObject(jObject));
        }

        public void Emit(string eventName, JArray param) {
            if (string.IsNullOrWhiteSpace(eventName)) throw new Exception("eventName 是必须的");

            JObject jObject = new JObject { ["eventName"] = eventName };
            if (param != null) jObject["data"] = param;
            if (State == WebSocketState.Open) {
                Send(JsonConvert.SerializeObject(jObject));
            } else {
                throw new Exception("socket 未连接，不能发送消息");
            }
        }
    }
}
